<template>
  <div>
    <!-- 面包屑区域 -->
    <el-breadcrumb>
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>分类参数</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片区域 -->
    <el-card>
      <!-- 头部警告区域，因为closable属性时布尔值类型，所以前面需要加上:表示动态绑定 -->
      <el-alert show-icon title="注意：只允许为第三级分类设置相关参数！" type="warning" :closable="false">
      </el-alert>

      <!-- 选择商品分类区域 -->
      <el-row class="cat_opt">
        <el-col>
          <span>选择商品分类：</span>
          <!-- 级联选择框 -->
          <el-cascader
            v-model="selectedCateKeys"
            :options="cateList"
            :props="cateProps"
            @change="handleChange" clearable>
          </el-cascader>
        </el-col>
      </el-row>

      <!-- tab页签区域 -->
      <el-tabs v-model="activeName" @tab-click="handleTabClick">
        <!-- 添加动态参数的面板 -->
        <el-tab-pane label="动态参数" name="many">
          <el-button type="primary" size="mini" :disabled="selectedCateKeys.length !== 3" 
          @click="addDialogVisible = true">
            添加参数
          </el-button>

          <!-- 动态参数表格 -->
          <el-table :data="manyTableData" border stripe>
            <!-- 展开列 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <!-- 用for循环渲染el-tag标签 -->
                <el-tag class="el-tag" closable v-for="(item, index) in scope.row.attr_vals" :key="index"
                @close="handleClose(scope.row, index)">
                  {{ item }}
                </el-tag>

                <!-- 输入的文本框 -->
                <!-- v-if和v-model绑定每一行自己的数据 -->
                <el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" ref="saveTagInput" size="small" 
                @keyup.enter.native="handleInputConfirm(scope.row)" @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <!-- 添加的按钮 -->
                <!-- 如果直接传过去scope.row.inputVisible的话是一个false值，没有办法修改值 -->
                <el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index"></el-table-column>
            <el-table-column label="参数名称" prop="attr_name"></el-table-column>
            <el-table-column label="操作" >
              <template slot-scope="scope">
                <!-- 注意：这里不是scope.row.id了，而是scope.row.attr_id -->
                <el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.attr_id)">编辑</el-button>
                <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeById(scope.row.attr_id)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <!-- 添加静态属性的面板 -->
        <el-tab-pane label="静态属性" name="only">
          <el-button type="primary" size="mini" :disabled="selectedCateKeys.length !== 3"
          @click="addDialogVisible = true">
            添加属性
          </el-button>

          <!-- 静态属性表格 -->
          <el-table :data="onlyTableData" border stripe>
            <!-- 展开列 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <!-- 用for循环渲染el-tag标签 -->
                <el-tag class="el-tag" closable v-for="(item, index) in scope.row.attr_vals" :key="index"
                @close="handleClose(scope.row, index)">
                  {{ item }}
                </el-tag>

                <!-- 输入的文本框 -->
                <!-- v-if和v-model绑定每一行自己的数据 -->
                <el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" ref="saveTagInput" size="small" 
                @keyup.enter.native="handleInputConfirm(scope.row)" @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <!-- 添加的按钮 -->
                <!-- 如果直接传过去scope.row.inputVisible的话是一个false值，没有办法修改值 -->
                <el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index"></el-table-column>
            <el-table-column label="属性名称" prop="attr_name"></el-table-column>
            <el-table-column label="操作" >
              <template slot-scope="scope">
                <!-- 注意：这里不是scope.row.id了，而是scope.row.attr_id -->
                <el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.attr_id)">编辑</el-button>
                <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeById(scope.row.attr_id)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>

    </el-card>

    <!-- 添加动态参数和静态属性的对话框 -->
    <el-dialog
      :title="'添加' + titleText"
      :visible.sync="addDialogVisible"
      width="50%"
      @close="addDialogClosed"
    >
      <!-- 内容主题区域 -->
      <el-form
        :model="addForm"
        :rules="addFormRules"
        ref="addFormRef"
        label-width="70px"
      >
        <el-form-item :label="titleText" prop="attr_name" label-width="80px">
          <el-input v-model="addForm.attr_name"></el-input>
        </el-form-item>
      </el-form>

      <!-- 底部区域 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addParams">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 编辑动态参数和静态属性的对话框 -->
    <el-dialog
      :title="'添加' + titleText"
      :visible.sync="editDialogVisible"
      width="50%"
      @close="editDialogClosed"
    >
      <!-- 内容主题区域 -->
      <el-form
        :model="editForm"
        :rules="editFormRules"
        ref="editFormRef"
        label-width="70px"
      >
        <el-form-item :label="titleText" prop="attr_name" label-width="80px">
          <el-input v-model="editForm.attr_name"></el-input>
        </el-form-item>
      </el-form>

      <!-- 底部区域 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="editParams">确 定</el-button>
      </span>
    </el-dialog>

  </div>
</template>

<script>
export default {
  data() {
    return {
      cateList: [],
      // 级联选择框双向绑定到的数组
      selectedCateKeys: [], 
      // 级联选择框的配置对象，和Categories.vue中一样
      cateProps: {
        // value指定绑定的值
        value: 'cat_id',
        // label指定显示的值
        label: 'cat_name',
        // children指定子级
        children: 'children',
        // 以hover的方式显示
        expandTrigger: 'hover',
      },
      // 初始时，页签选中的名字
      activeName: 'many',
      // 动态参数的数据
      manyTableData: [],
      // 静态属性的数据
      onlyTableData: [],
      // 添加对话框的显示与隐藏
      addDialogVisible: false,
      addForm: {
        attr_name: ''
      },
      addFormRules: {
        attr_name: [
          { required: true, message: '请输入参数名称', trigger: 'blur' },
        ]
      },
      editDialogVisible: false,
      editForm: {},
      editFormRules: {
        attr_name: [
          { required: true, message: '请输入参数名称', trigger: 'blur' },
        ]
      },
      // // 控制按钮和文本框的显示与隐藏
      // inputVisible: false,
      // // 双向绑定文本框中输入的内容
      // inputValue: '',


    }
  },
  computed: {
    // 当前选中的三级分类的Id
    cateId() {
      // 选中了3级分类，就把id返回；否则，返回空
      if(this.selectedCateKeys.length === 3) {
        return this.selectedCateKeys[2];
      }
      return null;
    },
    // 动态计算添加对话框的标题的属性
    titleText() {
      // 必须要有return语句
      if(this.activeName === 'many') {
        return '动态参数';
      }else{
        return '静态属性';
      }
    }
  },
  created() {
    this.getCateList();
  },
  methods: {
    // 获取分类列表的方法，和Categories中的方法是一样的
    async getCateList() {
      // 发起请求，由于页码和页数是可选的，而type如果不写的话，默认是获取所有级别的分类数据，而这里刚好符合要求，不需要传递参数
      const {data: res} = await this.$http.get('categories');
      if(res.meta.status !== 200) return this.$message.error('获取商品分类数据失败');
      // 请求成功，res.data里面的result才是真正存放商品分类数据的地方
      // console.log(res.data);
      this.cateList = res.data;
      // console.log(this.cateList);

    },
    // 级联选择框选中项变化，会触发这个函数
    handleChange() {
      this.getParamsData();
    },
    // 处理页签点击事件的函数
    handleTabClick() {
      console.log(this.activeName);
      this.getParamsData();
    },
    // 抽取出来公共的函数，用于发起请求，获取分类参数数据
    async getParamsData() {
      // 只允许选中3级分类，如果选中的不是3级分类就将它清空
      if(this.selectedCateKeys.length !== 3) {
        this.selectedCateKeys = [];
        this.manyTableData = [];
        this.onlyTableData = [];
        // 直接结束后面的代码
        return ;
      }
      // 选中了3级分类
      // console.log(this.selectedCateKeys);
      // 发起请求，获取数据
      const {data: res} = await this.$http.get(`categories/${this.cateId}/attributes`, {params: {sel: this.activeName}});
      if(res.meta.status !== 200) return this.$message.error('获取参数列表数据失败');
      // this.$message.success('成功获取参数列表数据');
      // console.log(res.data);
      // 将attr_vals转化为以空格分隔的数组，需要进行判空
      res.data.forEach(item => {
        // 如果是新增加的一个参数，由于item.attr_vals是空，三元表达式会将其进行隐式转换，Boolean('') = false
        item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : [];
        // 让每一行都能控制自己的隐藏和输入的值
        item.inputVisible = false;
        item.inputValue = '';
      });
      // 因为要渲染2个表格，所以需要分开存储
      if(this.activeName === 'many') {
        this.manyTableData = res.data;
      }else{
        this.onlyTableData = res.data;
      }
      console.log("many", this.manyTableData);
      console.log("only", this.onlyTableData);
    },    

    // 监听添加对话框的关闭事件
    addDialogClosed() {
      this.$refs.addFormRef.resetFields();
    },
    // 点击确定后触发的函数
    addParams() {
      // 先对表单做预验证，验证通过了再发起请求
      this.$refs.addFormRef.validate(async valid => {
        const {data: res} = await this.$http.post(`categories/${this.cateId}/attributes`, {
          attr_name: this.addForm.attr_name,
          attr_sel: this.activeName
        });
        if(res.meta.status !== 201) return this.$message.error('添加参数数据失败');
        this.$message.success('添加参数数据成功');
        this.addDialogVisible = false;
        this.getParamsData();
      })
    },
    // 点击编辑，弹出编辑参数的对话框
    async showEditDialog(id) {

      // console.log(id);
      // 先发起请求，获取到要修改的文本
      const {data: res} = await this.$http.get(`categories/${this.cateId}/attributes/${id}`, {
        params: {
          attr_sel: this.activeName
        }
      });
      console.log(res);
      if(res.meta.status !== 200) return this.$message.error('获取分类参数数据失败');
      // this.$message.success('成功');
      // 响应数据成功的时候，往表单对象上存放一份数据
      this.editForm = res.data;
      // 成功获取后，再打开对话框
      this.editDialogVisible = true;


    },
    editDialogClosed() {
      this.$refs.editFormRef.resetFields();
    },
    // 点击确定时，进行预校验，验证通过的话，就允许修改
    editParams() {
      this.$refs.editFormRef.validate(async valid => {
        if (!valid) return;
        // 如果合法，发起真正的修改角色的网络请求，
        // 因为之前把响应的数据往editForm中存放了一份，所以这里面已经有了attr_id这个属性了
        const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${this.editForm.attr_id}`,
          {
            attr_name: this.editForm.attr_name,
            attr_sel: this.activeName
          }
        );
        // console.log(res);
        if (res.meta.status !== 200) return this.$message.error("编辑参数失败");
        this.editDialogVisible = false;
         // 重新获取参数列表的数据
        this.getParamsData();
        // 提示编辑参数成功
        this.$message.success("编辑参数成功");
      })
    },
    // 删除参数的方法
    async removeById(id) {
      // 1.弹出提示框，函数的返回值是promise 所以可以用asyc和await来优化
      const confirmResult = await this.$confirm('此操作将永久删除该参数, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err) /* 点取消则由catch捕获异常 return err的简写 把err返回 */

      // 使用了async和await后：
      // 如果用户确认删除，则返回值为字符串 confirm
      // 如果用户取消了删除，则返回值为字符串 cancel
      if(confirmResult !== 'confirm') return this.$message.info('取消了删除参数');
      // 点击确认后，发起请求
      const {data: res} = await this.$http.delete(`categories/${this.cateId}/attributes/${id}`);
      if(res.meta.status !== 200) return this.$message.error('删除该参数失败');
      // 重新渲染
      this.getParamsData();
      // 提示信息
      this.$message.success('成功删除该参数');
    },
    // 文本框失去焦点或按下了回车都会触发这个函数
    handleInputConfirm(row) {
      // console.log("ok");
      // 切换走之前先看看输入的合不合法 不合法就清空再走 下次再打开来就不会显示这个了 trim是去除字符串两端的空格
      if(row.inputValue.trim().length === 0) {
        row.inputVisible = false;
        row.inputValue = '';
        return ;
      }
      // 如果没有return，则证明输入的内容合法
      // 把输入框中的值存放到数组中，以供循环显示
      row.attr_vals.push(row.inputValue.trim());
      row.inputVisible = false;
      // 把之前存放的值给清空
      row.inputValue = '';
      // 发起网络请求，做持久化
      this.saveAttrVals(row);      
    },
    // 点击按钮，显示文本框
    showInput(row) {
      // console.log(row);
      row.inputVisible = true;
      // 让文本框自动获得焦点
      // $nextTick 方法的作用，就是等文本输入框渲染出来之后，才会调用函数里的代码 还没渲染出来就获取input对象就去调用focus方法就会报错
      this.$nextTick(_ => {
        this.$refs.saveTagInput.$refs.input.focus();
      });
    },
    // 处理tag标签关闭的函数
    handleClose(row, index) {
      // splice方法会改变原数组，修改完后直接将其提交到服务器
      row.attr_vals.splice(index, 1);
      // 还是和之前上面一样，发起put请求，由于上面handleInputConfirm中写了一份，考虑到复用性，将其抽离出来，封装成一个函数
      this.saveAttrVals(row);
    },
    // 请求保存tag数组 attr_vals
    async saveAttrVals(row) {
      const {data: res} = await this.$http.put(`categories/${this.cateId}/attributes/${row.attr_id}`, {
        attr_name: row.attr_name,
        attr_sel: row.attr_sel,
        // row.attr_vals是一个数组，而在服务器中存放的是一个字符串，所以需要将其转化成字符串
        attr_vals: row.attr_vals.join(' ')
      });
      if(res.meta.status !== 200) return this.$message.error('编辑参数失败');
      this.$message.success('编辑参数成功');
    },



  },
}
</script>

<style lang="less" scoped>
  .cat_opt {
    margin: 20px;
  }

  .el-tag {
    margin: 5px;
  }

  .input-new-tag {
    width: 120px;
  }


</style>